# Multi-stage Dockerfile for a Nuxt 3 application
# Builder stage: install dev deps and build the app
FROM docker.1ms.run/node:22-alpine AS builder
WORKDIR /app

# Copy package files first for layer caching, but delay running `npm ci`
# until after the full source is copied so postinstall (nuxt prepare)
# can see project files and generate proper entries.
COPY package*.json ./

# Copy the full source (including scripts) before installing, to ensure
# postinstall hooks such as `nuxt prepare` run with the full project.
COPY . .

# Install build dependencies (run postinstall with full source available)
# Install system build tools so native modules (optional bindings) can be
# compiled on Alpine (musl). This avoids missing native bindings like
# @oxc-parser/binding-linux-x64-musl during `nuxt prepare`.
# We set npm_config_build_from_source=true for the install so native
# modules are built from source when prebuilds are not available.
RUN apk add --no-cache python3 build-base make g++ linux-headers && \
	# Workaround for npm optional-deps bug: if package-lock.json exists
	# npm may skip platform-specific optional bindings. Use `npm i` when
	# package-lock.json is present to let npm compute and install the
	# correct optional package for musl. Otherwise `npm ci` is used for
	# deterministic installs.
	if [ -f package-lock.json ]; then \
		# Workaround: move package-lock.json out of the way inside the build
		# container so `npm i` regenerates a lockfile appropriate for the
		# current platform (this addresses the npm optional-deps bug). The
		# original file is moved to /tmp and won't affect the host repo.
		mv package-lock.json /tmp/package-lock.json.bak || true; \
		npm_config_build_from_source=true npm i --no-audit --progress=false; \
	else \
		npm_config_build_from_source=true npm ci --no-audit --progress=false; \
	fi
# Some downstream packages reference an odd path inside `unenv` (runtime/runtime/...)
# If the real file exists at `dist/runtime/mock/empty.mjs`, copy it to the path
# that some imports look for so the build won't fail.
RUN if [ -f node_modules/unenv/dist/runtime/mock/empty.mjs ]; then \
			mkdir -p node_modules/unenv/dist/runtime/runtime/mock && \
			cp node_modules/unenv/dist/runtime/mock/empty.mjs node_modules/unenv/dist/runtime/runtime/mock/empty.mjs; \
		fi

RUN npm run build

# Remove devDependencies to keep only production deps. We do this in the builder
# so we don't need to run `npm ci --only=production` in the slimmer runtime image
# (which would trigger `postinstall` scripts that require dev-only packages).
RUN npm prune --production

# Runtime stage: install only production deps and copy built output
FROM docker.1ms.run/node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# 配置上海时区：设置环境变量 + 安装 tzdata（alpine 基础镜像默认无时区数据）
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tzdata && \
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo $TZ > /etc/timezone

## Copy production node_modules and built output from builder
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.output ./.output

EXPOSE 3000

# Start the Nitro server produced by Nuxt
CMD ["node", ".output/server/index.mjs"]